package la.bbs558.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import la.bbs558.config.CustomIdGenerator;
import la.bbs558.dao.UserDataDao;
import la.bbs558.entity.*;
import la.bbs558.entity.enums.RedisKey;
import la.bbs558.entity.params.UserDataForAdminPage;
import la.bbs558.entity.params.UserVisitCollectPage;
import la.bbs558.entity.params.UserVisitParams;
import la.bbs558.service.*;
import la.bbs558.util.IpUtil;
import la.bbs558.util.Objs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 用户表(UserData)表服务实现类
 *
 * @author weihanmin
 * @since 2023-12-15 16:15:24
 */
@Service("userDataService")
@Slf4j
public class UserDataServiceImpl extends ServiceImpl<UserDataDao, UserData> implements UserDataService {

    @Resource
    private UserService userService;
    @Resource
    private UserVisitDayService userVisitDayService;
    @Resource
    private UserDataDao userDataDao;
    @Resource
    private UserVisitStatisticsService userVisitStatisticsService;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private CustomIdGenerator idGenerator;
    @Resource
    private UserVisitCollectService userVisitCollectService;
    @Resource
    private HttpServletRequest request;

    @Override
    public void updatePoints(Long userId, int points) {
        getBaseMapper().updateUserDataPoints(userId, points);
    }

    @Override
    public UserData initGetUserData(Long userId) {
        UserData userData = getUserDataByUserId(userId);
        if (userData != null) {
            return userData;
        }
        Integer count = userService.lambdaQuery().eq(User::getId, userId).count();
        Objs.isTrue(count > 0, "用户不存在");
        String inviteCode = RandomUtil.randomNumbers(6);
        while (verifyInviteCode(inviteCode) != null) {
            inviteCode = RandomUtil.randomNumbers(6);
        }
        new UserData().setUserId(userId).setInvitationCode(inviteCode).insert();
        return getUserDataByUserId(userId);
    }

    @Override
    public UserData verifyInviteCode(String code) {
        return lambdaQuery().select(UserData::getId, UserData::getUserId, UserData::getInvitationCode)
                .eq(UserData::getInvitationCode, code)
                .one();
    }

    @Override
    public void visit() {
        Object visitId;
        if(StpUtil.isLogin()){
            visitId = StpUtil.getLoginId();
        }else {
            visitId = IpUtil.getIp(request);
        }
        if (Objs.isInvalid(visitId)) {
            return;
        }
        //更新上次访问时间
        DateTime now = DateUtil.date();
        if (StpUtil.isLogin()) {
            //更连续登录天数
            long userId = Long.parseLong(visitId.toString());
            UserData userData = initGetUserData(userId);
            if (userData == null) {
                return;
            }
            Date lastVisitTime = Objs.getOrElse(userData.getLastVisitTime(), now);
            userData.setLastVisitTime(now);
            String key = RedisKey.USER_UPDATE_LOGIN_DAY.spaceName(userId);
            boolean calcLoginDay = Boolean.TRUE.equals(redisTemplate.hasKey(key));
            if (calcLoginDay) {
                return;
            }
            //是否满足连续登录
            DateTime stTime = DateUtil.beginOfDay(lastVisitTime);
            DateTime edTime = DateUtil.beginOfDay(now);
            boolean checkVisitTime = DateUtil.between(stTime, edTime, DateUnit.DAY) <= 1;
            //可以更新
            lambdaUpdate()
                    .setSql(checkVisitTime, "continuous_login_days = continuous_login_days + 1")
                    .setSql(!checkVisitTime, "continuous_login_days = 0")
                    .set(UserData::getLastVisitTime, now)
                    .eq(UserData::getUserId, userId)
                    .update();
            long betweenMs = DateUtil.betweenMs(now, DateUtil.endOfDay(now));
            redisTemplate.opsForValue().set(key, 1, betweenMs, TimeUnit.MILLISECONDS);
        }
        //更新用户每日访问次数
        UserVisitDay userVisitDay = new UserVisitDay();
        userVisitDay.setId(idGenerator.nextId(null).longValue());
        userVisitDay.setVisitId(visitId.toString());
        userVisitDay.setVisitCnt(1);
        String createDate = now.toString(DatePattern.NORM_DATE_FORMAT);
        userVisitDay.setCreateDate(createDate);
        userVisitDayService.saveOrUpdateVisitDay(userVisitDay);
        //更新系统每日访问次数
        UserVisitStatistics userVisitStatistics = new UserVisitStatistics();
        userVisitStatistics.setId(idGenerator.nextId(null).longValue());
        userVisitStatistics.setVisitCnt(1);
        userVisitStatistics.setCreateDate(createDate);
        userVisitStatisticsService.saveOrUpdateVisitCount(userVisitStatistics);

    }

    @Override
    public void getListForAdmin(UserDataForAdminPage page) {
        userDataDao.selectListForAdmin(page);
    }

    @Override
    public void visitCollect(UserVisitParams params) {
        if (Objs.isInvalid(params)) {
            return;
        }
        String ip = params.getIp();
        // 获取城市
        JSONObject ipInfo = IpUtil.getIpInfo(ip);
        String areaStr = "unknown";
        if(ipInfo != null){
            String city = ipInfo.getString("city");
            if(Objs.isInvalid(city)){
                city = "unknown";
            }
            String region = ipInfo.getString("region");
            if(Objs.isInvalid(region)){
                region = "unknown";
            }
            areaStr = region + "-" + city;
        }
        UserVisitCollect userVisitCollect = new UserVisitCollect();
        userVisitCollect.setSource(params.getSource());
        userVisitCollect.setIp(ip);
        userVisitCollect.setUserId(params.getUserId());
        userVisitCollect.setArea(areaStr);
        userVisitCollect.setOsName(params.getOsName());
        userVisitCollect.setBrowserName(params.getBrowserName());
        userVisitCollect.setUpdateTime(new Date());
        userVisitCollectService.insertOrUpdate(userVisitCollect);
    }

    @Override
    public UserVisitCollectPage getVisitCollectPageForAdmin(UserVisitCollectPage page) {
        return userVisitCollectService.lambdaQuery().orderByDesc(UserVisitCollect::getCreateTime).page(page);
    }

    private UserData getUserDataByUserId(Long userId) {
        return lambdaQuery()
                .eq(UserData::getUserId, userId)
                .one();
    }
}

